﻿using Amazon.S3;
using Amazon.S3.Model;

namespace PmSoft.Core.FileStorage.Providers;

/// <summary>
/// Amazon S3 文件存储提供商，实现 IFileStorageProvider 接口
/// </summary>
public class S3StorageProvider : IFileStorageProvider
{
	private readonly IAmazonS3 _s3Client;

	/// <summary>
	/// 构造函数，初始化 S3 客户端
	/// </summary>
	/// <param name="accessKey"></param>
	/// <param name="secretKey"></param>
	/// <param name="region"></param>
	public S3StorageProvider(string accessKey, string secretKey, string region)
	{
		_s3Client = new AmazonS3Client(accessKey, secretKey, region); ;
	}

	/// <summary>
	/// 异步保存文件到 S3
	/// </summary>
	/// <param name="args">保存文件参数</param>
	/// <returns>表示异步操作的任务</returns>
	public async Task SaveFileAsync(SaveFileArgs args)
	{
		try
		{
			using var stream = new MemoryStream(args.Data); // 创建内存流
			var request = new PutObjectRequest
			{
				BucketName = args.BucketName,
				Key = args.ObjectName,
				InputStream = stream
			};
			await _s3Client.PutObjectAsync(request).ConfigureAwait(false);
		}
		catch (AmazonS3Exception ex)
		{
			throw new InvalidOperationException($"保存文件到 S3 失败: {ex.Message}", ex);
		}
	}

	/// <summary>
	/// 同步保存文件到 S3
	/// </summary>
	/// <param name="args">保存文件参数</param>
	public void SaveFile(SaveFileArgs args)
	{
		SaveFileAsync(args).GetAwaiter().GetResult(); // 调用异步方法并等待结果
	}


	/// <summary>
	/// 异步删除 S3 中的文件
	/// </summary>
	/// <param name="args">删除文件参数</param>
	/// <returns>表示异步操作的任务</returns>
	public async Task DeleteFileAsync(DeleteFileArgs args)
	{
		try
		{
			var request = new DeleteObjectRequest
			{
				BucketName = args.BucketName,
				Key = args.ObjectName
			};
			await _s3Client.DeleteObjectAsync(request).ConfigureAwait(false);
		}
		catch (AmazonS3Exception ex)
		{
			throw new InvalidOperationException($"删除 S3 文件失败: {ex.Message}", ex);
		}
	}

	/// <summary>
	/// 同步删除 S3 中的文件
	/// </summary>
	/// <param name="args">删除文件参数</param>
	public void DeleteFile(DeleteFileArgs args)
	{
		DeleteFileAsync(args).GetAwaiter().GetResult();
	}

	/// <summary>
	/// 异步移动 S3 中的文件（通过复制和删除实现）
	/// </summary>
	/// <param name="args">移动文件参数</param>
	/// <returns>表示异步操作的任务</returns>
	public async Task MoveFileAsync(MoveFileArgs args)
	{
		try
		{
			// 复制文件到目标位置
			var copyRequest = new CopyObjectRequest
			{
				SourceBucket = args.SourceBucketName,
				SourceKey = args.SourceObjectName,
				DestinationBucket = args.DestBucketName,
				DestinationKey = args.DestObjectName
			};
			await _s3Client.CopyObjectAsync(copyRequest).ConfigureAwait(false);

			// 删除源文件
			var deleteRequest = new DeleteObjectRequest
			{
				BucketName = args.SourceBucketName,
				Key = args.SourceObjectName
			};
			await _s3Client.DeleteObjectAsync(deleteRequest).ConfigureAwait(false);
		}
		catch (AmazonS3Exception ex)
		{
			throw new InvalidOperationException($"移动 S3 文件失败: {ex.Message}", ex);
		}
	}

	/// <summary>
	/// 同步移动 S3 中的文件
	/// </summary>
	/// <param name="args">移动文件参数</param>
	public void MoveFile(MoveFileArgs args)
	{
		MoveFileAsync(args).GetAwaiter().GetResult();
	}

	/// <summary>
	/// 异步获取 S3 中的文件内容
	/// </summary>
	/// <param name="args">获取文件参数</param>
	/// <returns>文件数据对象，包含文件内容</returns>
	public async Task<FileData?> GetFileAsync(GetFileArgs args)
	{
		try
		{
			var request = new GetObjectRequest
			{
				BucketName = args.BucketName,
				Key = args.ObjectName
			};
			using var response = await _s3Client.GetObjectAsync(request).ConfigureAwait(false);
			using var memoryStream = new MemoryStream();
			await response.ResponseStream.CopyToAsync(memoryStream).ConfigureAwait(false);
			return new FileData { Data = memoryStream.ToArray() };
		}
		catch (AmazonS3Exception ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
		{
			return null; // 文件不存在时返回 null
		}
		catch (AmazonS3Exception ex)
		{
			throw new InvalidOperationException($"获取 S3 文件失败: {ex.Message}", ex);
		}
	}

	/// <summary>
	/// 同步从 S3 获取文件
	/// </summary>
	/// <param name="args">获取文件参数</param>
	/// <returns>文件数据对象，如果文件不存在则返回 null</returns>
	public FileData? GetFile(GetFileArgs args)
	{
		return GetFileAsync(args).GetAwaiter().GetResult(); // 调用异步方法并等待结果
	}

	/// <summary>
	/// 异步检查 S3 中的文件是否存在
	/// </summary>
	/// <param name="args">检查文件参数</param>
	/// <returns>文件是否存在</returns>
	public async Task<bool> FileExistsAsync(FileExistsArgs args)
	{
		try
		{
			var request = new GetObjectMetadataRequest
			{
				BucketName = args.BucketName,
				Key = args.ObjectName
			};
			await _s3Client.GetObjectMetadataAsync(request).ConfigureAwait(false);
			return true;
		}
		catch (AmazonS3Exception ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
		{
			return false;
		}
		catch (AmazonS3Exception ex)
		{
			throw new InvalidOperationException($"检查 S3 文件存在性失败: {ex.Message}", ex);
		}
	}

	/// <summary>
	/// 同步判断文件在 S3 中是否存在
	/// </summary>
	/// <param name="args">判断文件是否存在参数</param>
	/// <returns>布尔值，表示文件是否存在</returns>
	public bool FileExists(FileExistsArgs args)
	{
		return FileExistsAsync(args).GetAwaiter().GetResult(); // 调用异步方法并等待结果
	}
}
